package android_dhbw.gpx;

import java.util.ArrayList;
import java.util.List;

import de.dhbw.GpsTools.AdvancedTrack;

public class SuppCalculator {
	
	private AdvancedTrack track;
	private List<Boolean> supportList;
	private List<Integer> categoryList = new ArrayList<Integer>();
	private List<Double> energyList = new ArrayList<Double>();
	private List<Double> energyOfCategories = new ArrayList<Double>();
	private List<Double> distanceOfCategories = new ArrayList<Double>();
	
	private double m_wTotal = 609000;
	private double m_rollCoeff = 0.0045;
	private double m_aeroCoeff = 0.8;
	private double m_veloAVG = 7;
	private double m_massDriver = 70;
	private double m_massBike = 20;
	private double m_frontSurface = 1;
	
	
	
	public SuppCalculator( AdvancedTrack track )
	{
		this.track = track;
		//processTrack();
	}
	
	public void setParameters(double wTotal, double rollCoeff, double aeroCoeff, double veloAVG, double massDriver, double massBike, double frontSurface)
	{
		m_wTotal = wTotal;
		m_rollCoeff = rollCoeff;
		m_aeroCoeff = aeroCoeff;
		m_veloAVG = veloAVG;
		m_massDriver = massDriver;
		m_massBike = massBike;
		m_frontSurface = frontSurface;
	}
	
	
	public List<Boolean> getSupporterList()
	{
		return supportList;
	}
	
	public List<Integer> getCategoryList()
	{
		return categoryList;
	}
	
	public double getPotentialEnergy()
	{
		double energy = 0;
		for (int i = 0; i < energyOfCategories.size(); i++)
		{
			if (energyOfCategories.get(i) != null)
			{
				energy += energyOfCategories.get(i);
			}
		}
		return energy;
	}
	
	public boolean processTrack()
	{
		List<Double> distances = track.getDistances();
		List<Double> elevations = getDeltaElevations(track.getElevations());
		double ratio;
		double partialEnergy;
		
		for (int i = 0; i < elevations.size(); i++)
		{
			if (distances.get(i) == 0)
			{
				ratio = 0;
			}
			else
			{
				ratio = elevations.get(i) / distances.get(i);
			}
			
			partialEnergy = (m_massDriver + m_massBike) * 9.81 * elevations.get(i);
			energyList.add(partialEnergy);
			
			if (ratio <= 0)
			{
				categoryList.add(-2);
			}
			else if (ratio <= 0.0175)
			{
				categoryList.add(1);
			}
			else if (ratio <= 0.0349)
			{
				categoryList.add(2);
			}
			else if (ratio <= 0.0523)
			{
				categoryList.add(3);
			}
			else if (ratio <= 0.0698)
			{
				categoryList.add(4);
			}
			else if (ratio <= 0.0872)
			{
				categoryList.add(5);
			}
			else if (ratio <= 0.1045)
			{
				categoryList.add(6);
			}
			else if (ratio <= 0.1219)
			{
				categoryList.add(7);
			}
			else if (ratio <= 0.1392)
			{
				categoryList.add(8);
			}
			else if (ratio <= 0.1564)
			{
				categoryList.add(9);
			}
			else if (ratio <= 0.1736)
			{
				categoryList.add(10);
			}
			else if (ratio <= 0.1908)
			{
				categoryList.add(11);
			}
			else if (ratio <= 0.2079)
			{
				categoryList.add(12);
			}
			else if (ratio <= 0.2250)
			{
				categoryList.add(13);
			}
			else if (ratio <= 0.2419)
			{
				categoryList.add(14);
			}
			else if (ratio <= 0.2588)
			{
				categoryList.add(15);		
			}
			else
			{
				categoryList.add(-1);
			}
		}
		
		calcEnergy();
		setSupportList();
		
		return true;
	}
	
	private boolean calcEnergy()
	{
		double tempEnergy;
		double tempDistance;
		List<Double> distances = track.getDistances();
		
		for(int i = 1; i <= 15; i++)
		{
			tempEnergy = 0;
			tempDistance = 0;
			
			for(int j = 0; j < energyList.size(); j++)
			{
				if (categoryList.get(j) == i)
				{
					tempEnergy += energyList.get(j);
					tempDistance += distances.get(j);
				}
			}
			
			energyOfCategories.add(tempEnergy);
			distanceOfCategories.add(tempDistance);
		}
		
		return true;
	}
	
	private boolean setSupportList()
	{
		supportList = new ArrayList<Boolean>(categoryList.size());
		
		double w = m_wTotal;
		double vAVG = m_veloAVG;
		double wTemp;
		double time;
		double rho = 1.2;
		double pRollApprox = m_rollCoeff * (m_massDriver + m_massBike) * 9.81 * vAVG;
		double pAero = 0.5 * m_aeroCoeff * rho * m_frontSurface * Math.pow(vAVG, 3);
		
		for (int i = 0; i < categoryList.size(); i++)
		{
			supportList.add(false);
		}
		
		for (int i = 15; i >= 1; i--)
		{
			time = distanceOfCategories.get(i-1) / vAVG;
			wTemp = (pRollApprox + pAero) * time + energyOfCategories.get(i-1);
			energyOfCategories.set(i-1, wTemp);
			
			if (wTemp <= w)
			{
				for(int j = 0; j < categoryList.size(); j++)
				{
					if (categoryList.get(j) == i)
					{
						supportList.set(j, true);
					}
				}
			}
			else if (wTemp > w)
			{
				setSupportListHelper(w, i);
			}
			else
			{
				i = 0;
			}
			
			w -= wTemp;
			
		}
		
		return true;
	}
	
	private void setSupportListHelper(double wRest, int category)
	{
		for(int i = categoryList.size(); i > 0; i--)
		{
			if (categoryList.get(i-1) == category)
			{
				if (wRest >= energyList.get(i-1))
				{
					supportList.set(i, true);
					wRest -= energyList.get(i-1);
				}
			}
		}
	}
	
	private List<Double> getDeltaElevations( List<Double> elevations)
	{
		List<Double> deltaElevations = new ArrayList<Double>();
		
		for (int i = 1; i < elevations.size(); i++)
		{
			deltaElevations.add(elevations.get(i) - elevations.get(i-1));
		}
		
		return deltaElevations;
	}

}
